package com.slipper.system.scheduled;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.lang.StringUtils;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;

import com.slipper.PaasContext;
import com.slipper.system.api.schedule.bo.ScheduleBO;
import com.slipper.system.api.schedule.bo.ScheduleLogBO;
import com.slipper.system.api.schedule.service.IScheduleLogSv;

/**
 * 定时任务
 */
public class ScheduledJob extends QuartzJobBean {
    public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";

    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final ExecutorService service = Executors.newSingleThreadExecutor();

    @Override
    protected void executeInternal(JobExecutionContext context) {
        ScheduleLogBO scheduleLogBO = null;
        ScheduleBO scheduleBO = null;
        long startTime = 0;
        IScheduleLogSv scheduleLogSv = PaasContext.getBean(IScheduleLogSv.class);

        try {
            scheduleBO = (ScheduleBO) context.getMergedJobDataMap().get(JOB_PARAM_KEY);
    
            // 判断此任务是否已在执行，如果任务已执行记录执行日志并立即退出
            ScheduleLogBO qo = new ScheduleLogBO();
            qo.setTaskId(scheduleBO.getId());
            if (scheduleLogSv.isRunning(qo).getData()) {
                scheduleLogBO = new ScheduleLogBO();
                scheduleLogBO.setTaskId(scheduleBO.getId());
                scheduleLogBO.setBeanName(scheduleBO.getBeanName());
                scheduleLogBO.setMethodName(scheduleBO.getMethodName());
                scheduleLogBO.setParams(scheduleBO.getParams());
                scheduleLogBO.setStatus(ScheduleLogBO.STATUS_FAILURE);
                scheduleLogBO.setErrorMessage("任务已在执行！");
                scheduleLogBO.setStartTime(new Date());
                scheduleLogBO.setEndTime(new Date());
                scheduleLogBO.setTimeConsume(0L);
                scheduleLogBO.setCreateTime(new Date());
                scheduleLogSv.save(scheduleLogBO);
                
                return;
            }
            
            // 任务开始时间
            startTime = System.currentTimeMillis();
            
            // 数据库保存执行记录
            scheduleLogBO = new ScheduleLogBO();
            scheduleLogBO.setTaskId(scheduleBO.getId());
            scheduleLogBO.setBeanName(scheduleBO.getBeanName());
            scheduleLogBO.setMethodName(scheduleBO.getMethodName());
            scheduleLogBO.setParams(scheduleBO.getParams());
            scheduleLogBO.setStatus(ScheduleLogBO.STATUS_RUNNING);
            scheduleLogBO.setStartTime(new Date());
            scheduleLogBO.setCreateTime(new Date());
            ScheduleLogBO persit = scheduleLogSv.save(scheduleLogBO).getData();
            scheduleLogBO.setId(persit.getId());

            // 执行任务
            logger.info("任务准备执行，任务ID: {}, bean: {}, method: {}, params: {}",
                    scheduleBO.getId(), scheduleBO.getBeanName(), 
                    scheduleBO.getMethodName(), scheduleBO.getParams());
            ScheduledRunnable schedule = new ScheduledRunnable(
                    scheduleBO, scheduleBO.getBeanName(), 
                    scheduleBO.getMethodName(), scheduleBO.getParams());
            Future<?> future = service.submit(schedule);
            future.get();

            // 任务执行总时长
            long timeConsume = System.currentTimeMillis() - startTime;
            scheduleLogBO.setTimeConsume(timeConsume);
            scheduleLogBO.setStatus(ScheduleLogBO.STATUS_SUCCESS);
            scheduleLogBO.setEndTime(new Date());
            scheduleLogSv.save(scheduleLogBO);

            logger.info("任务执行完毕，任务ID: {}, bean: {}, method: {}, params: {}, 总共耗时: {} 毫秒",
                    scheduleBO.getId(), scheduleBO.getBeanName(), scheduleBO.getParams(), 
                    scheduleBO.getMethodName(), timeConsume);
        } catch (Exception e) {
            logger.error(String.format("任务执行失败，任务ID: %s, bean: %s, method: %s",
                    scheduleBO == null ? "" : scheduleBO.getId(),
                    scheduleBO == null ? "" : scheduleBO.getBeanName(), 
                    scheduleBO == null ? "" : scheduleBO.getMethodName()), e);

            if (scheduleLogBO != null) {
                // 任务执行总时长
                long timeConsume = System.currentTimeMillis() - startTime;
                scheduleLogBO.setTimeConsume(timeConsume);
                scheduleLogBO.setStatus(ScheduleLogBO.STATUS_FAILURE);
                scheduleLogBO.setEndTime(new Date());
                scheduleLogBO.setErrorMessage(StringUtils.substring(e.toString(), 0, 2000));
                scheduleLogSv.save(scheduleLogBO);
            }
        }
    }
}
